﻿// 卡卡AI行为树

using System;
using System.Collections.Generic;

namespace AIClient.Utils
{
    public enum NodeState
    {
        Ready
      , Running
      , Success
      , Failed
    }

    public enum NodeType
    {
        Action
      , Condition
      , WaitUntil
      , Wait
      , Sequence
      , Select
      , Not
      , Parallel
    }

    public class BehaviourTree
    {
        private BTNode _rootNode;
        private BTNode _lastRuningNode; // 记住running结点,下次从此开始

        public NodeState State { get; private set; } // 行为树状态

        public BehaviourTree(BTNode node)
        {
            _rootNode = node;
        }

        // 行为树更新
        public NodeState Update()
        {
            State = _rootNode.OnVisit();
            return State;
        }

        // 重置
        public void Reset()
        {
            State = NodeState.Ready;
            _rootNode.Reset();
        }
    }

    public abstract class BTNode
    {
        public NodeState State { get; protected set; }

        public NodeType Type { get; private set; }

        protected BTNode(NodeType type)
        {
            Type = type;
        }

        public abstract NodeState OnVisit();

        public virtual void Reset()
        {
            State = NodeState.Ready;
        }
    }

    public abstract class BTCompositeNode : BTNode
    {
        protected readonly List<BTNode> ChildNodes;

        protected BTCompositeNode(List<BTNode> nodes, NodeType type) : base(type)
        {
            ChildNodes = nodes ?? new List<BTNode>();
        }

        public virtual BTCompositeNode AddChild(BTNode node)
        {
            ChildNodes.Add(node);
            return this;
        }

        public override void Reset()
        {
            foreach (var node in ChildNodes)
                node.Reset();
        }
    }

    #region 叶子节点

    // 动作节点,构造时传入Action
    public class ActionNode : BTNode
    {
        private Action _action;

        public ActionNode(Action action, int index = 0) : base(NodeType.Action)
        {
            _action = action;
        }

        public override NodeState OnVisit()
        {
            _action?.Invoke();
            return NodeState.Success;
        }
    }

    //  条件节点,构造时传入Func<bool>
    public class ConditionNode : BTNode
    {
        private Func<bool> _checkFunc;

        public ConditionNode(Func<bool> checkFunc) : base(NodeType.Condition)
        {
            _checkFunc = checkFunc;
        }

        public override NodeState OnVisit()
        {
            if (_checkFunc == null)
                return NodeState.Success;

            return _checkFunc.Invoke() ? NodeState.Success : NodeState.Failed;
        }
    }

    // 等待直到节点,传入脱离条件
    public class WaitUntilNode : BTNode
    {
        private Func<bool> _chekFunc;

        public WaitUntilNode(Func<bool> checkFunc) : base(NodeType.WaitUntil)
        {
            _chekFunc = checkFunc;
        }

        public override NodeState OnVisit()
        {
            if (_chekFunc == null)
                return NodeState.Success;

            return _chekFunc.Invoke() ? NodeState.Success : NodeState.Running;
        }
    }

    //// 等待节点,构造时传入要等待的时间
    //public class WaitNode : BTNode
    //{
    //    private int   _waitStartTime;
    //    private float _waitTime;

    //    public WaitNode(float waitTime) : base(NodeType.Wait)
    //    {
    //        _waitTime = waitTime;
    //    }

    //    public override NodeState OnVisit()
    //    {
    //        if (_waitStartTime == 0)
    //        {
    //            _waitStartTime = Manager.Instance.TimeStamp;
    //            State          = NodeState.Running;
    //        }

    //        if (Manager.Instance.TimeStamp < _waitStartTime + _waitTime)
    //            return State;

    //        State = NodeState.Success;
    //        return State;
    //    }

    //    public override void Reset()
    //    {
    //        _waitTime = 0;
    //        State     = NodeState.Ready;
    //    }
    //}

    #endregion

    #region 复合节点 

    // 顺序节点,按次序执行节点,当有节点Failed/Running时返回Failed,Runing,当所有为Success时返回Success
    public class SequenceNode : BTCompositeNode
    {
        public SequenceNode(List<BTNode> nodes = null) : base(nodes, NodeType.Sequence)
        {
        }

        public override NodeState OnVisit()
        {
            foreach (var node in ChildNodes)
            {
                var result = node.OnVisit();
                if (result == NodeState.Success) continue;

                State = result;
                return State;
            }

            State = NodeState.Success;
            return State;
        }
    }

    // 选择节点,按次序执行节点,当有节点为Success/Running时返回,所有执行为Failed时返回Failed
    public class SelectNode : BTCompositeNode
    {
        public SelectNode(List<BTNode> nodes = null) : base(nodes, NodeType.Select)
        {
        }

        public override NodeState OnVisit()
        {
            foreach (var node in ChildNodes)
            {
                var result = node.OnVisit();
                if (result == NodeState.Failed) continue;

                State = result;
                return State;
            }

            State = NodeState.Failed;
            return State;
        }
    }

    // 反转节点
    public class NotNode : BTCompositeNode
    {
        public NotNode(BTNode node) : base(new List<BTNode> {node}, NodeType.Not)
        {
        }

        public override NodeState OnVisit()
        {
            var result = ChildNodes[0].OnVisit();
            switch (result)
            {
                case NodeState.Failed:
                    return NodeState.Success;
                case NodeState.Success:
                    return NodeState.Failed;
                default:
                    return result;
            }
        }

        public override BTCompositeNode AddChild(BTNode node)
        {
            if (ChildNodes.Count == 0) return base.AddChild(node);

            Logger.LogError("取反节点已经有一个child了");
            return this;
        }
    }

    //  并行节点,执行所有节点,当所有节点都Success时返回Success,否则返回Failed
    public class ParallelNode : BTCompositeNode
    {
        public ParallelNode(List<BTNode> nodes = null) : base(nodes, NodeType.Parallel)
        {
        }

        public override NodeState OnVisit()
        {
            var tResult = NodeState.Success;
            foreach (var node in ChildNodes)
            {
                var result = node.OnVisit();
                if (result == NodeState.Failed)
                    tResult = result;
            }

            return tResult;
        }
    }

    #endregion
}